#include "IMoveable.h"
#include <math.h>
#include "MemTrack.h"

namespace bs
{
	IMoveable::IMoveable()
		: w(0), h(0), x(0.0f), y(0.0f), vx(0.0f), vy(0.0f), ax(0.0f), ay(0.0f), 
		friX(0.0f), friY(0.0f), maxVx(0.0f), maxVy(0.0f), minX(0.0f), maxX(0.0f), minY(0.0f), maxY(0.0f),
		collisionLeftOff(0), collisionTopOff(0), collisionRightOff(0), collistionBottomOff(0),
		outOfBounds(false), canMove(true), enableMaxVel(false), enableBounds(false), canMoveOut(false)
	{
	}

	IMoveable::~IMoveable()
	{
	}

	void IMoveable::DoMove(float speedFactor)
	{
		if(!this->canMove)
			return;

		this->x += this->vx * speedFactor;
		this->y += this->vy * speedFactor;

		this->CheckPos();

		this->vx += this->ax * speedFactor;
		this->vy += this->ay * speedFactor;

		this->AdjustVelWithFricrion(speedFactor);
		this->AdjustMaxVel();
	}

	bool IMoveable::CollisionWith( IMoveable* other )
	{
		if(!other)
			return false;

		return (x-w/2+collisionLeftOff < other->x+other->w/2-other->collisionRightOff
			&& x+w/2-collisionRightOff > other->x-other->w/2+other->collisionLeftOff
			&& y-h/2+collisionTopOff < other->y+other->h/2-other->collistionBottomOff
			&& y+h/2-collistionBottomOff > other->y-other->h/2+other->collisionTopOff);
	}

	void IMoveable::CheckPos()
	{
		if(!this->enableBounds)
			return;

		if(this->canMoveOut)
		{
			if(x+w/2<=minX || x-w/2>=maxX || y+h/2<=minY || y-y/2>=maxY)
			{
				if(!this->outOfBounds)
				{
					this->OnReachEdge();
					this->outOfBounds = true;
				}
			}
			else
			{
				this->outOfBounds = false;
			}
		}
		else
		{
			if(x-w/2 < minX)
			{
				this->x = minX + w/2;
				this->vx = this->ax = 0.0f;
			}
			else if(x+w/2 > maxX)
			{
				this->x = maxX - w/2;
				this->vx = this->ax = 0.0f;
			}

			if(y-h/2 < minY)
			{
				this->y = minY + h/2;
				this->vy = this->ay = 0.0f;
			}
			else if(y+h/2 > maxY)
			{
				this->y = maxY - h/2;
				this->vy = this->ay = 0.0f;
			}
		}
	}

	void IMoveable::AdjustVelWithFricrion(float speedFactor)
	{
		if(::abs(this->ax)<=0.001 && ::abs(this->vx)>0.001)
		{
			if(this->vx > 0)
			{
				this->vx -= this->friX * speedFactor;
			}
			else
			{
				this->vx += this->friX * speedFactor;
			}

			if(::abs(this->vx) <= this->friX*speedFactor)
			{
				this->vx = 0;
			}
		}

		if(::abs(this->ay)<=0.001 && ::abs(this->vy)>0.001)
		{
			if(this->vy > 0)
			{
				this->vy -= this->friY * speedFactor;
			}
			else
			{
				this->vy += this->friY * speedFactor;
			}

			if(::abs(this->vy) <= this->friY*speedFactor)
			{
				this->vy = 0;
			}
		}
	}

	void IMoveable::AdjustMaxVel()
	{
		if(!this->enableMaxVel)
			return;
		
		if(this->maxVx < this->vx)
		{
			this->vx = this->maxVx;
		}
		else if(this->maxVx < -this->vx)
		{
			this->vx = -this->maxVx;
		}

		if(this->maxVy < this->vy)
		{
			this->vy = this->maxVy;
		}
		else if(this->maxVy < -this->vy)
		{
			this->vy = -this->maxVy;
		}
	}
}

